package com.yiquan.comment.service;

import java.util.*;

import javax.jws.soap.SOAPBinding;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import com.yiquan.comment.dao.ThumbDao;
import com.yiquan.comment.feign.UserClient;
import com.yiquan.comment.feign.VideoClient;
import com.yiquan.comment.pojo.Thumb;
import com.yiquan.comment.pojo.UserActivity;
import entity.PageResult;
import entity.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import util.IdWorker;

import com.yiquan.comment.dao.CommentDao;
import com.yiquan.comment.pojo.Comment;

/**
 * 服务层
 *
 * @author Administrator
 */
@Service
@Slf4j
public class CommentService {

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private ThumbDao thumbDao;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private VideoClient videoClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private RedisTemplate redisTemplate;


    private static final String COMMENT_MODULE_ID = "COMMENT_MODULE_ID";

    private static Integer THUMB_STATUS = 0;
    private static Integer UN_THUMB_STATUS = 1;

    /**
     * 获取用户id (20000000-29999999)
     *
     * @return
     */
    public Long getUniqueId() {
        redisTemplate.opsForValue().setIfAbsent(COMMENT_MODULE_ID, 20000000L);
        Long temporaryUserId = redisTemplate.opsForValue().increment(COMMENT_MODULE_ID);
        return temporaryUserId;
    }

    /**
     * 查询全部列表
     *
     * @return
     */
    public List<Comment> findAll() {
        return commentDao.findAll();
    }

    /**
     * 获取当前视频下的一级评论（用户未登录状态下的）
     *
     * @param map 查询条件 parent_id = 视频id
     * @param page     页码
     * @param size     页大小
     * @return
     */
    public PageResult<Comment> findSearch(Map map, int page, int size) {

        Page<Comment> pageComment = getPageComment(map, page, size);
        //获取视频的用户id video_uid;
//        Long videoUseId = getUserIdByVideoId(map);
        pageComment.getContent().forEach((comment) -> {
            comment.setChildrenComments(commentDao.countChildCommentByTopId(comment.getId()));
            Result userResult = userClient.findByUserId(comment.getUser_id());
            LinkedHashMap<String, Object> userMap = (LinkedHashMap<String, Object>) userResult.getData();
            comment.setNick_name((String) userMap.get("nick_name")); //用户名称
            comment.setAvatar((String) userMap.get("avatar")); //用户头像
            comment.setThump_status(0); //设置评论的点赞状态
            Integer integer = commentDao.countChildCommentByTopId(comment.getId());
            if (integer ==null||integer==0){
                comment.setChildrenComments(0);
            }else {
                comment.setChildrenComments(integer);

            }
        });
        return new PageResult<>(pageComment.getTotalElements(), pageComment.getContent());
    }

    /**
     * 获取当前视频下的一级评论（用户登录状态下的）
     *
     * @param map 查询条件 parent_id = 视频id
     * @param page
     * @param size
     * @param userId  当前登录的用户id
     * @return
     */
    public PageResult<Comment> findSearchLogin(Map map, int page, int size, Long userId) {

        Page<Comment> pageComment = getPageComment(map, page, size);
        //获取视频的用户id video_uid;
//        Long videoUseId = getUserIdByVideoId(map);
        pageComment.getContent().forEach((comment) -> {
            comment.setChildrenComments(commentDao.countChildCommentByTopId(comment.getId()));
            Result userResult = userClient.findByUserId(comment.getUser_id());
            LinkedHashMap<String, Object> userMap = (LinkedHashMap<String, Object>) userResult.getData();
            comment.setNick_name((String) userMap.get("nick_name")); //用户名称
            comment.setAvatar((String) userMap.get("avatar")); //用户头像
            comment.setThump_status(0); //设置评论的点赞状态
            Thumb thumb = thumbDao.findOneByCommentIdAndUserId(comment.getId(), userId, THUMB_STATUS);
            if (!ObjectUtils.isEmpty(thumb)) {
                comment.setThump_status(THUMB_STATUS);
            } else {
                comment.setThump_status(UN_THUMB_STATUS);
            }

            Integer integer = commentDao.countChildCommentByTopId(comment.getId());
            if (integer ==null||integer==0){
                comment.setChildrenComments(0);
            }else {
                comment.setChildrenComments(integer);

            }

        });
        return new PageResult<>(pageComment.getTotalElements(), pageComment.getContent());
    }


    /**
     * 通过视频id获取视频作者id  uid(无效)
     *
     * @param map
     * @return
     */
    private Long getUserIdByVideoId(Map map) {
        Long video_id = (Long) map.get("parent_id");
        log.info("video_id:{}", video_id);
        Result videoResult = videoClient.findByVideoId(video_id);
        log.info("videoResult:{}", videoResult);
        LinkedHashMap<String, Object> videoMap = (LinkedHashMap<String, Object>) videoResult.getData();
        log.info("videoMap为:{}", videoMap);
        return (Long) videoMap.get("video_uid");
    }

    /**
     * 根据条件分页按评论时间顺序查询结果集(无效)
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    private List<Comment> getComments(Map whereMap, int page, int size) {
        //查询评论状态为0即正常的
        whereMap.put("comment_type", 0);
        //封装查询条件
        Specification<Comment> specification = createSpecification(whereMap);
        //建立排序条件(现在点赞数，再按评论时间)
        List<Sort.Order> orders = new ArrayList<>();
        orders.add(new Sort.Order(Sort.Direction.DESC, "thump"));
        orders.add(new Sort.Order(Sort.Direction.DESC, "commentDate"));
        Sort sort = Sort.by(orders);
        //分页+排序(按评论时间倒序)
        PageRequest pageRequest = PageRequest.of(page - 1, size, sort);

        //获取评论结果集
        return commentDao.findAll(specification, pageRequest).getContent();
    }

    /**
     * 根据条件分页按评论时间顺序查询结果集
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    public Page<Comment> getPageComment(Map whereMap, int page, int size) {
        //封装查询条件
        Specification<Comment> specification = createSpecification(whereMap);
        //建立排序条件(现在点赞数，再按评论时间)
        List<Sort.Order> orders = new ArrayList<>();
        orders.add(new Sort.Order(Sort.Direction.DESC, "thump"));
        orders.add(new Sort.Order(Sort.Direction.DESC, "commentDate"));
        Sort sort = Sort.by(orders);
        //分页+排序(按评论时间倒序)
        PageRequest pageRequest = PageRequest.of(page - 1, size, sort);
        return commentDao.findAll(specification, pageRequest);
    }

    /**
     * 条件查询+分页（用户登录状态下的） (无效)
     *
     * @param whereMap 查询条件
     * @param page     页码
     * @param size     页大小
     * @return
     */
    public PageResult<Comment> findSearch(Map whereMap, int page, int size, Long userId) {
        //根据条件分页按评论时间顺序查询结果集
        List<Comment> comments = getComments(whereMap, page, size);
        //获取视频的用户id video_uid;
        Long video_uid = getUserIdByVideoId(whereMap);
        for (Comment comment : comments) {
            //设置视频评论的子评论数
            if (0 == comment.getParent_type()) {
                Integer countByParentId = commentDao.findCountByParentId(comment.getId());
                comment.setChildrenComments(countByParentId);
            } else { //如果是子评论则设为0
                comment.setChildrenComments(0);
            }
            //判断该条评论是否为视频作者的评论
            if (comment.getUser_id().longValue() == video_uid.longValue()) { //该条评论是该视频作者评论
                comment.setCommentOfVideoAuthor(1);
            } else { //该条评论不是该视频作者评论
                comment.setCommentOfVideoAuthor(0);
            }
            //设置该条评论的用户名和头像
            Result userResult = userClient.findByUserId(comment.getUser_id());
            LinkedHashMap<String, Object> userMap = (LinkedHashMap<String, Object>) userResult.getData();
            comment.setNick_name((String) userMap.get("nick_name")); //用户名称
            comment.setAvatar((String) userMap.get("avatar")); //用户头像
            //登录用户id
            //判断返回评论是否被当前登录用户点赞，并设置评论的状态
            //设置评论点赞状态
            Thumb thumb = thumbDao.findOneByCommentIdAndUserId(comment.getId(), userId, 1);
            if (thumb != null) {//被点赞，修改评论状态
                comment.setThump_status(1);
            } else {//没有被点赞
                comment.setThump_status(0);
            }
        }
        //查询某条视频或某条评论下的评论总数
        Long count = getCount(whereMap);
        return new PageResult<Comment>(count, comments);
    }

    /**
     * 查询某条视频或某条评论下的评论总数
     *
     * @param whereMap
     * @return
     */
    private Long getCount(Map whereMap) {
        Long count = commentDao.findCount(whereMap.get("parent_id"), whereMap.get("parent_type"));
        //查询该视频的子评论总数
        if ((Integer) whereMap.get("parent_type") == 0) {
            Long childrenCount = commentDao.findChildrenCount(whereMap.get("parent_id"), whereMap.get("parent_type"));
            count += childrenCount;
        }
        return count;
    }


    /**
     * 条件查询
     *
     * @param whereMap 查询条件
     * @return
     */
    public List<Comment> findSearch(Map whereMap) {
        //查询评论状态为0即正常的
        whereMap.put("comment_type", 0);
        Specification<Comment> specification = createSpecification(whereMap);
        //根据评论创建时间排序
        Sort sort = Sort.by(Sort.Order.desc("commentDate"));
        return commentDao.findAll(specification, sort);
    }

    /**
     * 根据ID查询实体
     *
     * @param id 评论id
     * @return
     */
    public Comment findById(Long id) {
        return commentDao.findById(id).get();
    }

    /**
     * 增加
     *
     * @param comment
     */
    public void add(Comment comment, Long user_id) {

        comment.setUser_id(user_id);
        //设置初始点赞数
        comment.setThump(0);
        //设置评论状态为正常
        comment.setComment_type(0);
        //设置评论时间
        comment.setCommentDate(new Date());
        Comment save = commentDao.save(comment);
        Long commentId = save.getId();
        //评论 评论
        new Thread(()->{
            UserActivity userActivity = new UserActivity();
            if(comment.getTop_comment_id()!=null){
                userActivity.setActivity(3);
                userActivity.setFrom_user_id(user_id);
                userActivity.setTo_user_id(comment.getThe_user_id());
                userActivity.setBiz_no(commentId);
            }else {
                userActivity.setActivity(2);
                userActivity.setFrom_user_id(user_id);
                userActivity.setTo_user_id(comment.getThe_user_id());
                userActivity.setBiz_no(comment.getVideo_id());
            }
            userClient.addUserActivity(userActivity);
        }).run();
        //更新视频评论数
        updateComments(comment, 1);
    }

    /**
     * 更新视频评论数
     *
     * @param comment
     * @param modify
     */
    private void updateComments(Comment comment, Integer modify) {
        videoClient.modifyVideoCommentByVideoId(comment.getVideo_id(), modify);
    }

    /**
     * 修改
     *
     * @param comment
     */
    public void update(Comment comment) {
        commentDao.save(comment);
        //更新视频评论数
        //updateComments(comment,-1);
    }

    /**
     * 删除
     *
     * @param id 评论id
     */
    public void deleteById(Long id) {
        commentDao.updateCommentTypeById(id);
        updateComments(commentDao.findById(id).get(), -1);

    }

    /**
     * 动态条件构建
     *
     * @param searchMap
     * @return
     */
    private Specification<Comment> createSpecification(Map searchMap) {

        return new Specification<Comment>() {

            @Override
            public Predicate toPredicate(Root<Comment> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<Predicate>();

                if (searchMap.get("topCommentId") != null) {
                    predicateList.add(cb.equal(root.get("top_comment_id").as(Long.class), searchMap.get("topCommentId")));
                }

                if (searchMap.get("parent_id") != null) {
                    predicateList.add(cb.equal(root.get("parent_id").as(Long.class), searchMap.get("parent_id")));
                }

                if (searchMap.get("parent_type") != null) {
                    predicateList.add(cb.equal(root.get("parent_type").as(Integer.class), searchMap.get("parent_type")));
                }

                if (searchMap.get("comment_type") != null) {
                    predicateList.add(cb.equal(root.get("comment_type").as(Integer.class), searchMap.get("comment_type")));
                }

                if (searchMap.get("userId") != null) {
                    predicateList.add(cb.equal(root.get("user_id").as(Long.class), searchMap.get("parent_id")));
                }
                if (searchMap.get("commentId") != null) {
                    predicateList.add(cb.equal(root.get("id").as(Long.class), searchMap.get("commentId")));
                }


                return cb.and(predicateList.toArray(new Predicate[predicateList.size()]));

            }
        };

    }


    /**
     * 点赞/取消点赞
     *
     * @param comment
     * @return
     */
    @Transactional
    public String thump(Comment comment, Long userId) {
        //获取当前用户对该条评论的点赞状态
        Thumb hasThumb = thumbDao.findOneByCommentIdAndUserId(comment.getId(), userId, THUMB_STATUS);
        if (ObjectUtils.isEmpty(hasThumb)) {
            //增加点赞
            Thumb thumb = new Thumb();
            thumb.setUser_id(userId);
            thumb.setComment_id(comment.getId());
            thumb.setThump_status(THUMB_STATUS);
            //保存点赞信息到数据库
            thumbDao.save(thumb);
            Comment one = commentDao.getOne(comment.getId());
            one.setThump(one.getThump() + 1);
            commentDao.save(one);
            new Thread(()->{
                Comment byId = findById(comment.getId());
                UserActivity userActivity = new UserActivity();
                userActivity.setActivity(7);
                userActivity.setFrom_user_id(userId);
                userActivity.setTo_user_id(byId.getUser_id());
                userActivity.setBiz_no(byId.getId());
                userClient.addUserActivity(userActivity);
            }).run();
            return "点赞成功";
        } else {
            //取消点赞
            thumbDao.updateThumpStatusByCommentIdAndUserId(UN_THUMB_STATUS, comment.getId(), userId);
            Comment one = commentDao.getOne(comment.getId());
            one.setThump(one.getThump() - 1);
            commentDao.save(one);
            return "取消点赞成功";
        }

    }


    /**
     * 判断当前登录用户是否具有该评论的删除权限
     *
     * @param id
     * @return
     */
    public Boolean enableToDelete(Long id, String user_id_str) {
        Long user_id = Long.valueOf(user_id_str);
        Comment comment = commentDao.findById(id).get();
        if (comment.getUser_id().longValue() == user_id.longValue()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 用户后台搜索(按照评论时间倒序)
     *
     * @param searchMap
     * @param page
     * @param size
     * @return
     */
    public PageResult<Comment> backendSearch(Map searchMap, int page, int size) {
        Specification<Comment> specification = createSpecification(searchMap);
        PageRequest pageRequest = PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("commentDate")));
        //获取评论结果集
        List<Comment> content = commentDao.findAll(specification, pageRequest).getContent();
        long totalElements = commentDao.findAll(specification, pageRequest).getTotalElements();
        return new PageResult<Comment>(totalElements, content);
    }

    /**
     * 根据父评论查询子评论相关信息
     *
     * @param topCommentId
     * @param page
     * @param size
     * @param userId
     * @return
     */
    public PageResult<Comment> findCommentByTopCommentId(Long topCommentId, Integer page, Integer size, Long userId) {
        Map map = new HashMap();
        map.put("topCommentId", topCommentId);
        PageResult<Comment> search = null;
        if (userId == null) {
            search = findSearch(map, page, size);
        } else {
            search = findSearchLogin(map, page, size, userId);
        }
        assert search != null;
        search.getRows().forEach((comment) -> {
            Result userResult = userClient.findByUserId(comment.getUser_id());
            Result theUserResult = userClient.findByUserId(comment.getThe_user_id());
            Map data = (Map) userResult.getData();
            comment.setNick_name((String) data.get("nick_name"));
            Map data1 = (Map) theUserResult.getData();
            comment.setAvatar((String) data.get("avatar"));
            comment.setThe_nick_name((String) data1.get("nick_name"));
        });
        return search;
    }

    public void batchDelete(List<Long> commentIds) {
        commentIds.forEach(id->deleteById(id));
    }
}
